//this is a module that updates the value of hash
//Last modified by yangjao at 2021/5/12

module hash_update(
    input wire clk,
    input wire rst_n,
    input wire hash_reg_en,
    input wire update,
    input wire bigger16,
    input wire bigger32,
    input wire bigger64,
    input wire reset,
    input wire[1:0] S,
    input wire[31:0] W_i,
    input wire[31:0] W_i_4,
    input wire[31:0] W_j_7,
    input wire[31:0] W_j_16,

    output wire hash_Valid,
    output wire[7:0] data_out,
    output wire[31:0] W_j_7_add_W_j_16
);


reg[31:0] HRAM [0:7];
wire[31:0] A_out;
wire[31:0] B_out;
wire[31:0] C_in, C_out;
wire[31:0] D_out;
wire[31:0] E_in, E_out;
wire[31:0] F_out;
wire[31:0] G_in, G_out;
wire[31:0] H_out;

wire [31:0] Sigma0, Sigma1, CH, MAJ, K;

wire [31:0] SS1, SS2, FF, GG, P0, T, W_point;
wire [31:0] A_shift, B_shift, F_shift, SS1_A_shift;

wire [31:0] add1_in1, add1_in2, add1_out;
wire [31:0] add2_in1, add2_in2, add2_out;
wire [31:0] add3_in1, add3_in2, add3_out;
wire [31:0] add4_in1, add4_in2, add4_out;
wire [31:0] add5_in1, add5_in2, add5_out;
wire [31:0] add6_in1, add6_in2, add6_out;
wire [31:0] add7_in1, add7_in2, add7_out;
wire [31:0] add8_in1, add8_in2, add8_out;

wire [31:0] H0_in, H1_in, H2_in, H3_in, H4_in, H5_in, H6_in, H7_in;
wire [31:0] SM3_H0, SM3_H1, SM3_H2, SM3_H3, SM3_H4, SM3_H5, SM3_H6, SM3_H7;
wire [31:0] H0, H1, H2, H3, H4, H5, H6, H7;

Registers1 A(
    .clk(clk),
    .rst_n(rst_n),
    .reg_en(hash_reg_en),
    .data_in(add1_out),

    .data_out(A_out)
);

Registers1 B(
    .clk(clk),
    .rst_n(rst_n),
    .reg_en(hash_reg_en),
    .data_in(A_out),

    .data_out(B_out)
);

MUX_2_1 MUX17(
    .S(S[0]),
    .data_in1(B_out),
    .data_in2(B_shift),

    .data_out(C_in)
);

Registers1 C(
    .clk(clk),
    .rst_n(rst_n),
    .reg_en(hash_reg_en),
    .data_in(C_in),

    .data_out(C_out)
);

Registers1 D(
    .clk(clk),
    .rst_n(rst_n),
    .reg_en(hash_reg_en),
    .data_in(C_out),

    .data_out(D_out)
);

MUX_2_1 MUX18(
    .S(S[0]),
    .data_in1(add3_out),
    .data_in2(P0),

    .data_out(E_in)
);

Registers1 E(
    .clk(clk),
    .rst_n(rst_n),
    .reg_en(hash_reg_en),
    .data_in(E_in),

    .data_out(E_out)
);

Registers1 F(
    .clk(clk),
    .rst_n(rst_n),
    .reg_en(hash_reg_en),
    .data_in(E_out),
    
    .data_out(F_out)
);

MUX_2_1 MUX19(
    .S(S[0]),
    .data_in1(F_out),
    .data_in2(F_shift),

    .data_out(G_in)
);

Registers1 G(
    .clk(clk),
    .rst_n(rst_n),
    .reg_en(hash_reg_en),
    .data_in(G_in),

    .data_out(G_out)
);

Registers1 H(
    .clk(clk),
    .rst_n(rst_n),
    .reg_en(hash_reg_en),
    .data_in(G_out),

    .data_out(H_out)
);

MUX_2_1 MUX1(
    .S(S[1]),
    .data_in1(add7_out),
    .data_in2(H0),

    .data_out(add1_in1)
);

MUX_3_1 MUX2(
    .S(S),
    .data_in1(add2_out),
    .data_in2(add4_out),
    .data_in3(A_out),

    .data_out(add1_in2)
);

Adder add1(
    .a(add1_in1),
    .b(add1_in2),

    .sum(add1_out)
);

MUX_3_1 MUX3(
    .S(S),
    .data_in1(Sigma0),
    .data_in2(E_out),
    .data_in3(H1),

    .data_out(add2_in1)
);

MUX_3_1 MUX4(
    .S(S),
    .data_in1(MAJ),
    .data_in2(A_shift),
    .data_in3(B_out),

    .data_out(add2_in2)
);

Adder add2(
    .a(add2_in1),
    .b(add2_in2),

    .sum(add2_out)
);

MUX_3_1 MUX5(
    .S(S),
    .data_in1(add7_out),
    .data_in2(add5_out),
    .data_in3(H2),

    .data_out(add3_in1)
);

MUX_3_1 MUX6(
    .S(S),
    .data_in1(D_out),
    .data_in2(add6_out),
    .data_in3(C_out),

    .data_out(add3_in2)
);

Adder add3(
    .a(add3_in1),
    .b(add3_in2),

    .sum(add3_out)
);

MUX_3_1 MUX7(
    .S(S),
    .data_in1(Sigma1),
    .data_in2(FF),
    .data_in3(H3),

    .data_out(add4_in1)
);

MUX_3_1 MUX8(
    .S(S),
    .data_in1(CH),
    .data_in2(D_out),
    .data_in3(D_out),

    .data_out(add4_in2)
);

Adder add4(
    .a(add4_in1),
    .b(add4_in2),

    .sum(add4_out)
);

MUX_3_1 MUX9(
    .S(S),
    .data_in1(H_out),
    .data_in2(W_i),
    .data_in3(H4),

    .data_out(add5_in1)
);

MUX_3_1 MUX10(
    .S(S),
    .data_in1(K),
    .data_in2(SS1),
    .data_in3(E_out),

    .data_out(add5_in2)
);

Adder add5(
    .a(add5_in1),
    .b(add5_in2),

    .sum(add5_out)
);

MUX_3_1 MUX11(
    .S(S),
    .data_in1(add5_out),
    .data_in2(GG),
    .data_in3(H5),

    .data_out(add6_in1)
);

MUX_3_1 MUX12(
    .S(S),
    .data_in1(add4_out),
    .data_in2(H_out),
    .data_in3(F_out),

    .data_out(add6_in2)
);

Adder add6(
    .a(add6_in1),
    .b(add6_in2),

    .sum(add6_out)
);

MUX_3_1 MUX13(
    .S(S),
    .data_in1(add6_out),
    .data_in2(W_point),
    .data_in3(H6),

    .data_out(add7_in1)
);

MUX_3_1 MUX14(
    .S(S),
    .data_in1(W_i),
    .data_in2(SS1_A_shift),
    .data_in3(G_out),

    .data_out(add7_in2)
);

Adder add7(
    .a(add7_in1),
    .b(add7_in2),

    .sum(add7_out)
);

MUX_3_1 MUX15(
    .S(S),
    .data_in1(W_j_7),
    .data_in2(add2_out),
    .data_in3(H7),
    
    .data_out(add8_in1)
);

MUX_3_1 MUX16(
    .S(S),
    .data_in1(W_j_16),
    .data_in2(T),
    .data_in3(H_out),

    .data_out(add8_in2)
);

Adder add8(
    .a(add8_in1),
    .b(add8_in2),

    .sum(add8_out)
);

Sigma0_generator Sigma_0(
    .data_in(A_out),
    .data_out(Sigma0)
);

Sigma1_generator Sigma_1(
    .data_in(E_out),
    .data_out(Sigma1)
);

MAJ_generator MAJ1(
    .data_in1(A_out),
    .data_in2(B_out),
    .data_in3(C_out),
    .data_out(MAJ)
);

CH_generator CH1(
    .data_in1(E_out),
    .data_in2(F_out),
    .data_in3(G_out),
    .data_out(CH)
);

K_generator K1(
    .clk(clk),
    .rst_n(rst_n),
    .reg_en(hash_reg_en),
    .restart(reset),

    .data_out(K)
);


shift12 shift_1(
    .data_in(A_out),
    .data_out(A_shift)
);

shift9 shift_2(
    .data_in(B_out),
    .data_out(B_shift)
);

shift19 shift_3(
    .data_in(F_out),
    .data_out(F_shift)
);

T_generator T1(
    .clk(clk),
    .rst_n(rst_n),
    .hash_reg_en(hash_reg_en),
    .bigger32(bigger32),
    .bigger15(bigger15),
    .bigger64(bigger64),
    .restart(reset),
    .T(T)
);

shift7 shift_4(
    .data_in(add8_out),
    .data_out(SS1)
);

XOR xor1(
    .data_in1(A_shift),
    .data_in2(SS1),

    .data_out(SS1_A_shift)
);

XOR xor2(
    .data_in1(W_i),
    .data_in2(W_i_4),

    .data_out(W_point)
);

FF_generator FF1(
    .bigger15(bigger15),
    .data_in1(A_out),
    .data_in2(B_out),
    .data_in3(C_out),

    .data_out(FF)
);

GG_generator GG1(
    .bigger15(bigger15),
    .data_in1(E_out),
    .data_in2(F_out),
    .data_in3(G_out),

    .data_out(GG)
);

P0_generator P1(
    .data_in(add3_out),
    .data_out(P0)
);

XOR xor3(
    .data_in1(H0),
    .data_in2(A_out),

    .data_out(SM3_H0)
);

XOR xor4(
    .data_in1(H1),
    .data_in2(B_out),
    
    .data_out(SM3_H1)
);

XOR xor5(
    .data_in1(H2),
    .data_in2(C_out),

    .data_out(SM3_H2)
);

XOR xor6(
    .data_in1(H3),
    .data_in2(D_out),

    .data_out(SM3_H3)
);

XOR xor7(
    .data_in1(H4),
    .data_in2(E_out),

    .data_out(SM3_H4)
);

XOR xor8(
    .data_in1(H5),
    .data_in2(F_out),

    .data_out(SM3_H5)
);

XOR xor9(
    .data_in1(H6),
    .data_in2(G_out),

    .data_out(SM3_H6)
);

XOR xor10(
    .data_in1(H7),
    .data_in2(H_out),

    .data_out(SM3_H7)
);


MUX_2_1 MUX20(
    .S(S[0]),
    .data_in1(add1_out),
    .data_in2(SM3_H0),

    .data_out(H0_in)
);

MUX_2_1 MUX21(
    .S(S[0]),
    .data_in1(add2_out),
    .data_in2(SM3_H1),

    .data_out(H1_in)
);

MUX_2_1 MUX22(
    .S(S[0]),
    .data_in1(add3_out),
    .data_in2(SM3_H2),

    .data_out(H2_in)
);

MUX_2_1 MUX23(
    .S(S[0]),
    .data_in1(add4_out),
    .data_in2(SM3_H3),

    .data_out(H3_in)
);

MUX_2_1 MUX24(
    .S(S[0]),
    .data_in1(add5_out),
    .data_in2(SM3_H4),

    .data_out(H4_in)
);

MUX_2_1 MUX25(
    .S(S[0]),
    .data_in1(add6_out),
    .data_in2(SM3_H5),

    .data_out(H5_in)
);

MUX_2_1 MUX26(
    .S(S[0]),
    .data_in1(add7_out),
    .data_in2(SM3_H6),

    .data_out(H6_in)
);

MUX_2_1 MUX27(
    .S(S[0]),
    .data_in1(add8_out),
    .data_in2(SM3_H7),

    .data_out(H7_in)
);

HRAM HRAM1(
    .clk(clk),
    .rst_n(rst_n),
    .reset(reset),
    .update(update),
    .select(S[0]),
    .in1(H0_in),
    .in2(H1_in),
    .in3(H2_in),
    .in4(H3_in),
    .in5(H4_in),
    .in6(H5_in),
    .in7(H6_in),
    .in8(H7_in),

    .hash_Valid(hash_Valid),
    .data_out(data_out),
    .out1(H0),
    .out2(H1),
    .out3(H2),
    .out4(H3),
    .out5(H4),
    .out6(H5),
    .out7(H6),
    .out8(H7)
);

endmodule
